////
/// @group progress
////

@use "sass:color";
@use "sass:map";
@use "../utils";
@use "../theme/colors";
@use "../theme/theme";
@use "../transition/transition";

/// Set to `true` to disable all the styles.
/// @type Boolean
$disable-everything: false !default;

/// Set to `true` to disable the `LinearProgress` styles.
/// @type Boolean
$disable-linear: $disable-everything !default;

/// Set to `true` to disable the `LinearProgress` vertical styles.
/// @type Boolean
$disable-linear-vertical: false !default;

/// Set to `true` to disable the `LinearProgress` horizontal styles.
/// @type Boolean
$disable-linear-horizontal: false !default;

/// Set to `true` to disable the `LinearProgress` reversed styles.
/// @type Boolean
$disable-linear-reverse: false !default;

/// Set to `true` to only disable the `CircularProgress` styles.
/// @type Boolean
$disable-circular: $disable-everything !default;

/// Set to `true` to disable the `CircularProgress` centered styles.
/// @type Boolean
$disable-circular-centered-styles: false !default;

/// Set this to `true` if the rotate-only animation is not needed for the
/// `CircularProgress`.
/// @type Boolean
$disable-circular-rotate-only: false !default;

/// Set to `true` to disable only the determinate progress styles.
/// @type Boolean
$disable-determinate: false !default;

/// Set to `true` to disable only the indeterminate progress styles.
/// @type Boolean
$disable-indeterminate: false !default;

/// This is the default prominent color for the `LinearProgress` component
/// that helps indicate the current progress. This covers the
/// `$background-color`.
///
/// @see $background-color
/// @type Color
$color: theme.theme-get-var(primary-color) !default;

/// This is the default background-color/secondary color for the
/// `LinearProgress` component that is used as the full track color. This is
/// covered by the `$color`.
///
/// @see $color
/// @type Color
$background-color: color-mix(in srgb, currentcolor 66%, colors.$white) !default;

/// The default `CircularProgress` size.
/// @type Number
$circular-size: 3rem !default;

/// The default dense `CircularProgress` size.
/// @type Number
$circular-dense-size: 1.5rem !default;

/// The default svg `stroke-width` for the `CircularProgress`.
/// @type Number
$circular-stroke-width: 6 !default;

/// The default svg `stroke-dasharray` for the `CircularProgress`.
/// @type Number
$circular-dasharray: 187 !default;

/// The default transition duration for the determinate `CircularProgress` to
/// animate to new values.
/// @type Number
$circular-transition-duration: transition.$enter-duration !default;

/// The default transition duration for the indeterminate `CircularProgress`.
/// @type Number
$circular-indeterminate-transition-duration: 2.4s !default;

/// The default transition duration for the indeterminate `CircularProgress`
/// that only rotates to improve performance.
/// @type Number
$circular-rotate-only-transition-duration: 1.2s !default;

/// The default svg `stroke-dashoffset` for the indeterminate
/// `CircularProgress` that only rotates to improve performance.
/// @type Number
$circular-rotate-only-dashoffset: $circular-dasharray * 0.4 !default;

/// The default starting `stroke-dashoffset` for the `CircularProgress`
/// animation.
/// @type Number
$circular-start-offset: $circular-dasharray !default;

/// The default ending `stroke-dashoffset` for the `CircularProgress`
/// animation.
/// @type Number
$circular-end-offset: $circular-dasharray * 0.25 !default;

/// Used to generate the `@keyframes rmd-progress-rotate` for the indeterminate
/// `CircularProgress`.
/// @type Map
$circular-rotate-styles: (
  0%: (
    transform: rotate(0deg),
  ),
  50%: (
    transform: rotate(135deg),
  ),
  75%: (
    transform: rotate(450deg),
  ),
  100%: (
    transform: rotate(720deg),
  ),
) !default;

/// Used to generate the `@keyframes rmd-circular-progress-size` for the
/// indeterminate `CircularProgress`.
/// @type Map
$circular-dash-styles: (
  0%: (
    stroke-dashoffset: $circular-start-offset,
  ),
  50%: (
    stroke-dashoffset: $circular-end-offset,
  ),
  100%: (
    stroke-dashoffset: $circular-start-offset,
  ),
) !default;

/// The default height/width for the `LinearProgress`.
/// @type Number
$linear-size: 0.25rem !default;

/// The default transition duration for the `LinearProgress` keyframes
/// animation.
/// @type Number
$linear-transition-duration: 2.4s !default;

/// The default transition duration for the `LinearProgress` keyframes
/// animation that is a bit quicker.
/// @type Number
$linear-short-animation-delay: 0.75s !default;

/// Used to generate the `@keyframes rmd-progress-bar` for the
/// indeterminate `LinearProgress`.
/// @type Map
$linear-styles: (
  0%: (
    left: -35%,
    right: 100%,
  ),
  60%: (
    left: 100%,
    right: -90%,
  ),
  100%: (
    left: 100%,
    right: -90%,
  ),
) !default;

/// Used to generate the `@keyframes rmd-progress-bar-short` for the
/// indeterminate `LinearProgress`.
/// @type Map
$linear-short-styles: (
  0%: (
    left: -200%,
    right: 100%,
  ),
  40%: (
    left: 107%,
    right: -8%,
  ),
  100%: (
    left: 107%,
    right: -8%,
  ),
) !default;

/// Used to generate the `@keyframes rmd-progress-bar-reverse` for the
/// reversed indeterminate `LinearProgress`.
/// @type Map
$linear-reverse-styles: (
  0%: (
    left: 100%,
    right: -35%,
  ),
  60%: (
    left: -90%,
    right: 100%,
  ),
  100%: (
    left: -90%,
    right: 100%,
  ),
) !default;

/// Used to generate the `@keyframes rmd-progress-bar-reverse-short` for the
/// reversed indeterminate `LinearProgress` that is a bit quicker.
/// @type Map
$linear-reverse-short-styles: (
  0%: (
    left: 100%,
    right: -200%,
  ),
  40%: (
    left: -8%,
    right: 107%,
  ),
  100%: (
    left: -8%,
    right: 107%,
  ),
) !default;

/// Used to generate the `@keyframes rmd-progress-bar-vertical` for the
/// vertical indeterminate `LinearProgress`.
/// @type Map
$linear-vertical-styles: (
  0%: (
    bottom: -35%,
    top: 100%,
  ),
  60%: (
    bottom: 100%,
    top: -90%,
  ),
  100%: (
    bottom: 100%,
    top: -90%,
  ),
) !default;

/// Used to generate the `@keyframes rmd-progress-bar-vertical-short` for the
/// vertical indeterminate `LinearProgress` that is a bit quicker.
/// @type Map
$linear-vertical-short-styles: (
  0%: (
    bottom: -200%,
    top: 100%,
  ),
  40%: (
    bottom: 107%,
    top: -8%,
  ),
  100%: (
    bottom: 107%,
    top: -8%,
  ),
) !default;

/// Used to generate the `@keyframes rmd-progress-bar-vertical-reversed` for the
/// vertical reversed indeterminate `LinearProgress`.
/// @type Map
$linear-vertical-reverse-styles: (
  0%: (
    bottom: 100%,
    top: -35%,
  ),
  60%: (
    bottom: -90%,
    top: 100%,
  ),
  100%: (
    bottom: -90%,
    top: 100%,
  ),
) !default;

/// Used to generate the `@keyframes rmd-progress-bar-vertical-reversed-short`
/// for the vertical reversed indeterminate `LinearProgress` that is a bit
/// quicker.
/// @type Map
$linear-vertical-reverse-short-styles: (
  0%: (
    bottom: 100%,
    top: -200%,
  ),
  40%: (
    bottom: -8%,
    top: 107%,
  ),
  100%: (
    bottom: -8%,
    top: 107%,
  ),
) !default;

/// The available configurable css variables and mostly used internally for the
/// `get-var`, `set-var`, and `use-var` utils.
/// @type List
$variables: (
  background-color,
  color,
  circular-size,
  circular-stroke-width,
  linear-size
);

/// @param {String} name - The supported variable name
/// @param {any} fallback [null] - An optional fallback value
/// @returns {String} a `var()` statement
@function get-var($name, $fallback: null) {
  $var: utils.get-var-name($variables, $name, "progress");
  @if $fallback {
    @return var(#{$var}, #{$fallback});
  }

  @return var(#{$var});
}

/// @param {String} name - The supported variable name
/// @param {any} value - The value to set the variable to. Supports `null` which
/// will just be a no-op.
@mixin set-var($name, $value) {
  @if $value {
    #{utils.get-var-name($variables, $name, "progress")}: #{$value};
  }
}

/// @param {String} property - The css property to apply the variable to
/// @param {String} name [$property] - The supported variable name
/// @param {any} fallback [null] - An optional fallback value if the variable
/// has not been set
@mixin use-var($property, $name: $property, $fallback: null) {
  #{$property}: get-var($name, $fallback);
}

/// @param {Map} styles - The styles map to convert to keyframes
/// @access private
@mixin _animation($styles) {
  @if $styles {
    @each $percentage, $style in $styles {
      #{$percentage} {
        @include utils.map-to-styles($style);
      }
    }
  }
}

/// @access private
@mixin _circular-progress {
  .rmd-circular-progress {
    @include use-var(height, circular-size);
    @include use-var(width, circular-size);
    // add border radius and overflow-hidden so that different stroke-widths
    // are still circular. For some reason it isn't always the case.
    align-items: center;
    border-radius: 50%;
    display: inline-flex;
    justify-content: center;
    overflow: hidden;

    @if not $disable-circular-centered-styles {
      &--centered {
        display: flex;
        margin: 0 auto;
      }
    }

    @if $circular-dense-size {
      &--dense {
        @include set-var(circular-size, $circular-dense-size);
      }
    }

    &__svg {
      height: inherit;
      width: inherit;

      @if not $disable-determinate {
        &--determinate {
          transform: rotate(-90deg);
        }
      }

      @if not $disable-indeterminate {
        &--indeterminate {
          animation: rmd-progress-rotate
            $circular-indeterminate-transition-duration
            linear
            infinite;
        }

        @if not $disable-circular-rotate-only {
          &--rotate-only {
            animation: rmd-progress-rotate-only
              $circular-rotate-only-transition-duration
              linear
              infinite;
          }
        }
      }
    }

    &__circle {
      @include use-var(stroke-width, circular-stroke-width);

      fill: none;
      stroke: currentcolor;
      stroke-dasharray: $circular-dasharray;
      stroke-linecap: round;

      @if not $disable-determinate {
        &--animate {
          transition: stroke-dashoffset
            $circular-transition-duration
            transition.$linear-timing-function;
        }
      }

      @if not $disable-indeterminate {
        &--indeterminate {
          animation: rmd-circular-progress-size
            $circular-indeterminate-transition-duration
            ease-in-out
            infinite;
        }

        @if not $disable-circular-rotate-only {
          &--rotate-only {
            animation: none;
            stroke-dashoffset: $circular-rotate-only-dashoffset;
          }
        }
      }
    }
  }

  @if not $disable-circular-rotate-only {
    @keyframes rmd-progress-rotate-only {
      from {
        transform: rotate(0deg);
      }
      to {
        transform: rotate(360deg);
      }
    }
  }

  @if not $disable-indeterminate {
    @keyframes rmd-progress-rotate {
      @include _animation($circular-rotate-styles);
    }

    @keyframes rmd-circular-progress-size {
      @include _animation($circular-dash-styles);
    }
  }
}

/// @access private
@mixin _linear-progress-bar {
  @if not $disable-linear-horizontal {
    &--horizontal {
      left: 0;

      @include utils.rtl {
        left: auto;
        right: 0;
      }
    }

    @if not $disable-linear-reverse {
      &--horizontal-reverse {
        left: auto;
        right: 0;

        @include utils.rtl {
          left: 0;
          right: auto;
        }
      }
    }
  }

  @if not $disable-linear-vertical {
    &--vertical {
      bottom: 0;
      left: 0;
      right: 0;
    }

    @if not $disable-linear-reverse {
      &--vertical-reverse {
        bottom: auto;
        top: 0;
      }
    }
  }

  &--animate {
    transition-duration: transition.$linear-duration;
    transition-property: height, width;
    transition-timing-function: transition.$sharp-timing-function;
  }

  @if not $disable-determinate {
    &--determinate {
      @include use-var(
        background-color,
        color,
        theme.theme-color-var-fallback($color)
      );
      @include use-var(height, linear-size);

      position: absolute;
      z-index: 0;
    }
  }

  @if not $disable-indeterminate {
    &--indeterminate {
      &::before,
      &::after {
        @include use-var(
          background-color,
          color,
          theme.theme-color-var-fallback($color)
        );
        @include use-var(height, linear-size);

        animation-duration: $linear-transition-duration;
        animation-iteration-count: infinite;
        animation-timing-function: transition.$linear-timing-function;
        content: "";
        left: 0;
        position: absolute;
        right: 100%;
        will-change: left, right;
        z-index: 0;

        @include utils.rtl {
          left: 100%;
          right: 0;
        }
      }

      @if not $disable-linear-horizontal {
        &::before {
          animation-name: rmd-progress-bar;
        }

        &::after {
          animation-delay: $linear-short-animation-delay;
          animation-name: rmd-progress-bar-short;
        }
      }
    }

    @if not $disable-linear-reverse {
      &--indeterminate-reverse {
        &::before {
          animation-name: rmd-progress-bar-reverse;
        }

        &::after {
          animation-name: rmd-progress-bar-reverse-short;
        }
      }
    }

    @if not $disable-linear-vertical {
      &--indeterminate-vertical {
        &::before,
        &::after {
          @include use-var(width, linear-size);

          height: auto;
          left: 0;
          right: 0;
          will-change: top, bottom;
        }

        &::before {
          animation-name: rmd-progress-bar-vertical;
        }

        &::after {
          animation-name: rmd-progress-bar-vertical-short;
        }
      }

      @if not $disable-linear-reverse {
        &--indeterminate-vertical-reverse {
          &::before {
            animation-name: rmd-progress-bar-vertical-reverse;
          }

          &::after {
            animation-name: rmd-progress-bar-vertical-reverse-short;
          }
        }
      }
    }
  }
}

/// @access private
@mixin _linear-progress {
  .rmd-linear-progress {
    @include use-var(background-color);

    display: block;
    overflow: hidden;
    position: relative;

    @if not $disable-linear-horizontal {
      &--horizontal {
        @include use-var(height, linear-size);

        width: 100%;
      }
    }

    @if not $disable-linear-vertical {
      &--vertical {
        @include use-var(width, linear-size);

        display: inline-block;
        height: auto;
      }
    }

    &__bar {
      @include _linear-progress-bar;
    }
  }

  @if not $disable-linear-horizontal {
    @keyframes rmd-progress-bar {
      @include _animation($linear-styles);
    }

    @keyframes rmd-progress-bar-short {
      @include _animation($linear-short-styles);
    }

    @if not $disable-linear-reverse {
      @keyframes rmd-progress-bar-reverse {
        @include _animation($linear-reverse-styles);
      }

      @keyframes rmd-progress-bar-reverse-short {
        @include _animation($linear-reverse-short-styles);
      }
    }
  }

  @if not $disable-linear-vertical {
    @keyframes rmd-progress-bar-vertical {
      @include _animation($linear-vertical-styles);
    }

    @keyframes rmd-progress-bar-vertical-short {
      @include _animation($linear-vertical-short-styles);
    }

    @if not $disable-linear-reverse {
      @keyframes rmd-progress-bar-vertical-reverse {
        @include _animation($linear-vertical-reverse-styles);
      }

      @keyframes rmd-progress-bar-vertical-reverse-short {
        @include _animation($linear-vertical-reverse-short-styles);
      }
    }
  }
}

/// Conditionally applies the css variables based on feature flags
@mixin variables {
  @if not $disable-circular {
    @include set-var(circular-size, $circular-size);
    @include set-var(circular-stroke-width, $circular-stroke-width);
  }

  @if not $disable-linear {
    @include set-var(background-color, $background-color);
    @if not theme.is-theme-color-var($color) {
      @include set-var(color, $color);
    }
    @include set-var(linear-size, $linear-size);
  }
}

/// Generates all the styles based on feature flags.
///
/// @param {Boolean} disable-layer [false] - Set this to `true` to disable the
/// layer behavior
@mixin styles($disable-layer: false) {
  @include utils.optional-layer(
    progress,
    $disable-layer or ($disable-circular and $disable-linear)
  ) {
    @if not $disable-circular {
      @include _circular-progress;
    }

    @if not $disable-linear {
      @include _linear-progress;
    }
  }
}
